package com.kingdee.eas.custom.aoyuan.aytime.bizbill.app;

import org.apache.log4j.Logger;
import javax.ejb.*;
import java.rmi.RemoteException;
import java.sql.SQLException;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import com.kingdee.bos.*;
import com.kingdee.bos.util.BOSObjectType;
import com.kingdee.bos.util.BOSUuid;
import com.kingdee.bos.metadata.IMetaDataPK;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.bos.metadata.rule.RuleExecutor;
import com.kingdee.bos.metadata.MetaDataPK; //import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.framework.ejb.AbstractEntityControllerBean;
import com.kingdee.bos.framework.ejb.AbstractBizControllerBean; //import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.IObjectValue;
import com.kingdee.bos.dao.IObjectCollection;
import com.kingdee.bos.service.ServiceContext;
import com.kingdee.bos.service.IServiceContext;
import com.kingdee.eas.framework.app.CoreBillBaseControllerBean;
import com.kingdee.eas.framework.SystemEnum;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.dao.query.IQueryExecutor;
import com.kingdee.bos.dao.query.QueryExecutorFactory;
import com.kingdee.eas.framework.ObjectBaseCollection;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.basedata.org.HROrgUnitInfo;
import com.kingdee.eas.basedata.org.PositionFactory;
import com.kingdee.eas.basedata.org.PositionInfo;
import com.kingdee.eas.basedata.person.PersonCollection;
import com.kingdee.eas.basedata.person.PersonFactory;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.BasesettingCollection;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.BasesettingFactory;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.BasesettingInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleCollection;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleEntryInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleGroupFactory;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleGroupInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.SchedulePersonCollection;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.SchedulePersonEntryInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.SchedulePersonFactory;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.SchedulePersonInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.SchedulePersonSpecSchlInfo;
import com.kingdee.eas.custom.aoyuan.aytime.basedata.ScheduleFactory;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.AttenDetailInfo;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.CardRecordCollection;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.CardRecordFactory;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.CardRecordInfo;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.HolidayBillEntryCollection;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.HolidayBillEntryFactory;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.HolidayBillEntryInfo;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.HolidayBillFactory;

import java.lang.String;
import com.kingdee.eas.framework.CoreBillBaseCollection;
import com.kingdee.eas.custom.aoyuan.aytime.bizbill.AttenDetailCollection;
import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.metadata.entity.FilterInfo;
import com.kingdee.bos.metadata.entity.FilterItemInfo;
import com.kingdee.bos.metadata.entity.SorterItemCollection;
import com.kingdee.bos.metadata.entity.SorterItemInfo;
import com.kingdee.eas.framework.CoreBaseCollection;
import com.kingdee.eas.framework.CoreBaseInfo;
import com.kingdee.eas.hr.emp.PersonPositionCollection;
import com.kingdee.eas.hr.emp.PersonPositionFactory;
import com.kingdee.eas.hr.emp.PersonPositionInfo;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.bos.metadata.entity.SelectorItemCollection;

class CheckRegionClass {
	long stm;
	long etm;
	Boolean isFinish;
}

class TimeParam {
	Time cardTime = null;
	// 迟到时间
	long lateTime = 0;
	// 早退时间
	long earlyTime = 0;
	//旷工时间
	long absentTime = 0;
	boolean isFinish = false;
	boolean isNextDay = false;
	boolean isFind = false;
	//该班第一点上班
	boolean isFirstFind = false;
}

public class AttenDetailControllerBean extends
		AbstractAttenDetailControllerBean {
	private static Logger logger = Logger
			.getLogger("com.kingdee.eas.custom.aoyuan.aytime.bizbill.app.AttenDetailControllerBean");

	/*
	 * 后台事务定时计算考勤
	 * @see com.kingdee.eas.custom.aoyuan.aytime.bizbill.app.AbstractAttenDetailControllerBean#autoCalcAtten(com.kingdee.bos.Context)
	 */
	public void autoCalcAtten(Context ctx) throws BOSException {
		super.autoCalcAtten(ctx);
    	Calendar c = Calendar.getInstance();
    	c.setTime(new Date());
    	c.add(Calendar.DAY_OF_YEAR, -2);
    	logger.info("自动考勤计算开始：---------------------------------");
    	logger.info("计算日期："+c.getTime());
		EntityViewInfo evi = new EntityViewInfo();
		FilterInfo filter = new FilterInfo();
		filter.getFilterItems().add(
				new FilterItemInfo("number", "AY%", CompareType.LIKE));
		evi.setFilter(filter);
		PersonCollection personColl=PersonFactory.getLocalInstance(ctx).getPersonCollection(evi);
		for(int i=0;i<personColl.size();i++)
		{
			this.calcOnePersonAtten(ctx, personColl.get(i).getId().toString(), c.getTime());			
		}
    	logger.info("共计算："+personColl.size()+"条");
    	logger.info("计算结束：----------------------------------------");
	}
	
	
	/*
	 * 后台事务定时清除加班余额
	 * @see com.kingdee.eas.custom.aoyuan.aytime.bizbill.app.AbstractAttenDetailControllerBean#autoCleanHoliday(com.kingdee.bos.Context)
	 */
	public void autoCleanHoliday(Context ctx) throws BOSException {
		//super._autoCleanHoliday(ctx);
		String sql="/*dialect*/update ct_ay_personotbalance t set t.cfnormalot=0,t.cfweekenot=0,t.cfholidayot=0,t.cftotaluse=0 ";
    	logger.info("自动清除加班余额开始：---------------------------------");
		DbUtil.execute(ctx, sql);
    	logger.info("自动清除加班余额结束：---------------------------------");
	}



	/**
	 * 计算某天是否完成工作日，以踩点方式标识状态，当标记状态满足时，表示员工该班次正常上班。
	 * 
	 * @param ctx
	 * @param personid
	 * @param workDate
	 */
	private void calcOnePersonAtten(Context ctx, String personid, Date workDate) {
    	
		// 获取该用户班表

		// 获取用户HR组织
		String orgHrId = this.getOrgByPersonDate(ctx, personid, workDate);
		// 没有HR组织，不计算
		if (orgHrId == null)
			return;
		// 获取班组
		String schedulegroup = this.getScheduleForPersonOrg(ctx, personid,
				orgHrId);
		// 没有该HR组织的班组
		if (schedulegroup == null)
			return;
		// 获取该用户班表明细
		ScheduleEntryInfo schEntry = this.getDutyInfo(ctx, schedulegroup,
				workDate);
		
	 	 Calendar c = Calendar.getInstance();
		   c.setTime(workDate);
		   c.set(Calendar.HOUR, 0);
		   c.set(Calendar.MINUTE, 0);
		   c.set(Calendar.SECOND, 0);
		   Date startDate = c.getTime();
		   c.setTime(workDate);
		   c.set(Calendar.HOUR, 23);
		   c.set(Calendar.MINUTE, 59);
		   c.set(Calendar.SECOND, 59);
		   Date endDate = c.getTime();
		AttenDetailInfo attenDetailInfo = new AttenDetailInfo();
		AttenUtil attenUtil=new AttenUtil();
		if (schEntry == null) {
			deleteAttenDetail(ctx,personid,workDate);
			return;
		} else {
			//该班表没有设置时间，跳出
			if((schEntry.getSt1()!=null&&schEntry.getEt1()!=null)||(schEntry.getSt2()!=null&&schEntry.getEt2()!=null)){
				//2天的实际打卡记录（考虑跨日工作）
				ArrayList cards = this.getCardRecord(ctx, personid, workDate);
				ArrayList noHolidaylist=(ArrayList)cards.clone();
				// 处理请假的情况
				ArrayList cardsHoliday=getHolidayEntryRecord(ctx,personid,workDate);
				 //合并计算
				cards.addAll(cardsHoliday);
				
				// 是否中间休息，如有：4个打卡时间，无：即2个打卡时间
				if (schEntry.isIsRestCard()) {
					 
					//获得上午班第一次打卡
					TimeParam timeParam1=attenUtil.isFinishStartCardByOffice1(ctx,schEntry, cards, personid,workDate);
					
					//获得上午班第二次打卡
					TimeParam timeParam2=attenUtil.isFinishEndCardByOffice1(schEntry, cards);
					
					//获得下午班第三次打卡
					TimeParam timeParam3=attenUtil.isFinishStartCardByOffice2(schEntry, cards);
					
					//获得下午班第四次打卡
					TimeParam timeParam4=attenUtil.isFinishEndCardByOffice2(schEntry, cards);
					
					
					//该班次第一班第一次打卡，共4次
					boolean ok1=false;
					boolean ok2=false;
					boolean ok3=false;
					boolean ok4=false;
					
					//迟到总时间
					Long lateTime=0L;
					//早退总时间
					Long earlyTime=0L;
					//旷工总时间
					Long absentTime=0L;
					
					if(timeParam1.isFinish)
					{
						ok1=true;
						TimeParam timeParam11=attenUtil.isFinishStartCardByOffice1(ctx,schEntry, noHolidaylist, personid,workDate);
						attenDetailInfo.setSTime1(timeParam11.cardTime);
					}
					if(timeParam2.isFinish)
					{
						ok2=true;
						TimeParam timeParam22=attenUtil.isFinishEndCardByOffice1(schEntry, noHolidaylist);
						attenDetailInfo.setETime1(timeParam22.cardTime);
					}
					if(timeParam3.isFinish)
					{
						ok3=true;
						TimeParam timeParam33=attenUtil.isFinishStartCardByOffice2(schEntry, noHolidaylist);
						attenDetailInfo.setSTime2(timeParam33.cardTime);
					}
					if(timeParam4.isFinish)
					{
						ok4=true;
						TimeParam timeParam44=attenUtil.isFinishEndCardByOffice2(schEntry, noHolidaylist);
						attenDetailInfo.setETime2(timeParam44.cardTime);
					}
					
					//该班次完整打卡
					if(ok1&&ok2&&ok3&&ok4)
					{
						attenDetailInfo.setIsClose(true);
					}else{
						
						//第一班上班打卡没成功
						if(!ok1)
						{
							if(timeParam1.isFind)
							{
								//累加迟到时间
								lateTime+=timeParam1.lateTime;
								attenDetailInfo.setSTime1(timeParam1.cardTime);
							}else
							{
								//累加旷工时间
								absentTime+=timeParam1.absentTime;								
							}
						}
						//第一班下班打卡没成功
						if(!ok2)
						{
							if(timeParam2.isFind)
							{
								//累加早退时间
								earlyTime+=timeParam2.earlyTime;
								attenDetailInfo.setETime1(timeParam2.cardTime);
							}
						}
						//第二班上班打卡没成功
						if(!ok3)
						{
							if(timeParam3.isFind)
							{
								//累加迟到时间
								lateTime+=timeParam3.lateTime;	
								attenDetailInfo.setSTime2(timeParam3.cardTime);
							}else
							{
								//累加旷工时间
								absentTime+=timeParam3.absentTime;
							}
						}
						//第二班下班打卡没成功
						if(!ok4)
						{
							if(timeParam4.isFind)
							{
								//累加早退时间
								earlyTime+=timeParam4.earlyTime;		
								attenDetailInfo.setETime2(timeParam4.cardTime);
							}
						}
						attenDetailInfo.setIsClose(false);					
					}
					
					attenDetailInfo.setLateTime(lateTime.intValue());
					attenDetailInfo.setEarlyTime(earlyTime.intValue());
					attenDetailInfo.setAbsentTime(absentTime.intValue());
					
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					PersonInfo person = new PersonInfo();
					person.setId(BOSUuid.read(personid));
					attenDetailInfo.setEmp(person);
				 	Calendar c1 = Calendar.getInstance();
					c1.setTime(workDate);
					c1.set(Calendar.HOUR, 0);
					c1.set(Calendar.MINUTE, 0);
				    c1.set(Calendar.SECOND, 0);
				    c1.set(Calendar.MILLISECOND, 0);
					attenDetailInfo.setBizDate(c1.getTime());
					try {
						FilterInfo filter = new FilterInfo();
						filter.getFilterItems().add(
								new FilterItemInfo("emp", personid));
						filter.getFilterItems().add(new FilterItemInfo("bizDate",startDate,CompareType.GREATER_EQUALS));
						filter.getFilterItems().add(new FilterItemInfo("bizDate",endDate,CompareType.LESS_EQUALS));	 
						//删除历史的
						this.delete(ctx, filter);
						//保存最新的
						this.save(ctx, attenDetailInfo);
					} catch (EASBizException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BOSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				} else {
	                 //中间不休息
					//获得上午班第一次打卡
					TimeParam timeParam1=attenUtil.isFinishStartCardByOffice1(ctx,schEntry, noHolidaylist, personid,workDate);
					if((!timeParam1.isFinish))
					{
						//找到第一班，但迟到
					   if(cardsHoliday.size()>0)
					   {
						   TimeParam tmptimeParam=attenUtil.isFinishStartCardByOffice1(ctx,schEntry, cardsHoliday, personid,workDate);	
						   if(tmptimeParam.isFinish)
						   {
							   timeParam1=tmptimeParam;							   
						   }
					   }
					}
					
					//获得下午班第四次打卡
					TimeParam timeParam4=attenUtil.isFinishEndCardByOffice2(schEntry, cards);
					
					//该班次第一班第一次打卡，共2次
					boolean ok1=false;
					boolean ok4=false;
					
					//迟到总时间
					Long lateTime=0L;
					//早退总时间
					Long earlyTime=0L;
					//旷工总时间
					Long absentTime=0L;
					
					if(timeParam1.isFinish) 
					{
						ok1=true;
						TimeParam timeParam11=attenUtil.isFinishStartCardByOffice1(ctx,schEntry, noHolidaylist, personid,workDate);
						attenDetailInfo.setSTime1(timeParam11.cardTime);
					}
					if(timeParam4.isFinish)
					{
						ok4=true;
						TimeParam timeParam44=attenUtil.isFinishEndCardByOffice2(schEntry, noHolidaylist);
						attenDetailInfo.setETime2(timeParam44.cardTime);
					}
					//获得上午班第二次打卡
					TimeParam timeParam22=attenUtil.isFinishEndCardByOffice1(schEntry, noHolidaylist);
					attenDetailInfo.setETime1(timeParam22.cardTime);
					//获得下午班第三次打卡
					TimeParam timeParam33=attenUtil.isFinishStartCardByOffice2ByGroup(schEntry, noHolidaylist);
					attenDetailInfo.setSTime2(timeParam33.cardTime);
					
					//该班次完整打卡
					if(ok1&&ok4)
					{
						attenDetailInfo.setIsClose(true);
					}else{
						
						//第一班上班打卡没成功
						if(!ok1)
						{
							if(timeParam1.isFind)
							{
								//累加迟到时间
								lateTime+=timeParam1.lateTime;
								attenDetailInfo.setSTime1(timeParam1.cardTime);
							}else
							{
								//累加旷工时间
								absentTime+=timeParam1.absentTime;				
							}
						}
						//第二班下班打卡没成功
						if(!ok4)
						{
							if(timeParam4.isFind)
							{
								//累加早退时间
								earlyTime+=timeParam4.earlyTime;
								attenDetailInfo.setETime2(timeParam4.cardTime);
								//累加迟到时间
								lateTime+=timeParam4.lateTime;
							}else
							{
								//累加旷工时间
								absentTime+=timeParam4.absentTime;								
							}
						}
						attenDetailInfo.setIsClose(false);					
					}
					
					attenDetailInfo.setLateTime(lateTime.intValue());
					//System.out.println(lateTime.intValue());
					attenDetailInfo.setEarlyTime(earlyTime.intValue());
					attenDetailInfo.setAbsentTime(absentTime.intValue());
					
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					PersonInfo person = new PersonInfo();
					person.setId(BOSUuid.read(personid));
					HROrgUnitInfo hrOrg=new HROrgUnitInfo();
					hrOrg.setId(BOSUuid.read(orgHrId));
					attenDetailInfo.setHROrgUnit(hrOrg);
					attenDetailInfo.setEmp(person);
				 	Calendar c1 = Calendar.getInstance();
					c1.setTime(workDate);
					c1.set(Calendar.HOUR, 0);
					c1.set(Calendar.MINUTE, 0);
				    c1.set(Calendar.SECOND, 0);
				    c1.set(Calendar.MILLISECOND, 0);
					attenDetailInfo.setBizDate(c1.getTime());
					try {
						FilterInfo filter = new FilterInfo();
						filter.getFilterItems().add(
								new FilterItemInfo("emp", personid));
						filter.getFilterItems().add(new FilterItemInfo("bizDate",startDate,CompareType.GREATER_EQUALS));
						filter.getFilterItems().add(new FilterItemInfo("bizDate",endDate,CompareType.LESS_EQUALS));	
						//删除历史的
						this.delete(ctx, filter);
						//保存最新的
						this.save(ctx, attenDetailInfo);
					} catch (EASBizException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BOSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			
				}
			}
		}
	}
	
	private void deleteAttenDetail(Context ctx,String personid, Date workDate)
	{
	 	 Calendar c = Calendar.getInstance();
		   c.setTime(workDate);
		   c.set(Calendar.HOUR, 0);
		   c.set(Calendar.MINUTE, 0);
		   c.set(Calendar.SECOND, 0);
		   Date startDate = c.getTime();
		   c.setTime(workDate);
		   c.set(Calendar.HOUR, 23);
		   c.set(Calendar.MINUTE, 59);
		   c.set(Calendar.SECOND, 59);
		   Date endDate = c.getTime();
		try {
			FilterInfo filter = new FilterInfo();
			filter.getFilterItems().add(
					new FilterItemInfo("emp", personid));
			filter.getFilterItems().add(new FilterItemInfo("bizDate",startDate,CompareType.GREATER_EQUALS));
			filter.getFilterItems().add(new FilterItemInfo("bizDate",endDate,CompareType.LESS_EQUALS));	 
			//删除历史的
			this.delete(ctx, filter);
			//保存最新的
		} catch (EASBizException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BOSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	private AttenDetailInfo getAttenDetail(Context ctx,String personid, Date workDate)
	{
		EntityViewInfo evi = new EntityViewInfo();
		FilterInfo filter = new FilterInfo();
		filter.getFilterItems().add(
				new FilterItemInfo("Emp.id", personid));
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		filter.getFilterItems().add(
				new FilterItemInfo("BizDate", df.format(workDate)));
		SorterItemCollection sic = new SorterItemCollection();
		evi.setFilter(filter);
		try {
			AttenDetailCollection coll=this.getAttenDetailCollection(ctx, evi);
			if(coll.size()>0)
			{
				return coll.get(0);
			}
		} catch (BOSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		return null;
	}

	private ArrayList getHolidayEntryRecord(Context ctx, String personid,
			Date workDate) {
		ArrayList list = new ArrayList();
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		EntityViewInfo evi = new EntityViewInfo();
		FilterInfo filter = new FilterInfo();
		filter.getFilterItems().add(
				new FilterItemInfo("parent.status", "3", CompareType.EQUALS));
		filter.getFilterItems().add(
				new FilterItemInfo("parent.applier.id", personid));
		filter.getFilterItems().add(new FilterItemInfo("holidayType.htype", 2,CompareType.NOTEQUALS));
		filter.getFilterItems().add(
				new FilterItemInfo("BizDate", df.format(workDate)));

		filter.setMaskString("#0 and #1 and #2 and #3");
		SorterItemCollection sic = new SorterItemCollection();
		sic.add(new SorterItemInfo("BizDate"));
		evi.setFilter(filter);
		evi.setSorter(sic);
		try {
			HolidayBillEntryCollection entrys = HolidayBillEntryFactory
					.getLocalInstance(ctx).getHolidayBillEntryCollection(evi);

			Iterator it = entrys.iterator();

			while (it.hasNext()) {
				HolidayBillEntryInfo info = (HolidayBillEntryInfo) it.next();
				if(info.getEndTime()==null||info.getStartTime()==null)
				{
					continue;
				}
				CardRecordInfo startRecord = new CardRecordInfo();
				CardRecordInfo emdRecord = new CardRecordInfo();
				Calendar c = Calendar.getInstance();
				c.setTime(info.getEndTime());
				c.set(Calendar.YEAR, workDate.getYear()+1900);
				c.set(Calendar.MONTH, workDate.getMonth());
				c.set(Calendar.DATE, workDate.getDate());
				emdRecord.setBizTime(new Time(c.getTime().getTime()));
				emdRecord.setBizDate(new Time(c.getTime().getTime()));
				c.setTime(info.getStartTime());
				c.set(Calendar.YEAR, workDate.getYear()+1900);
				c.set(Calendar.MONTH, workDate.getMonth());
				c.set(Calendar.DATE, workDate.getDate());
				startRecord.setBizTime(new Time(c.getTime().getTime()));
				startRecord.setBizDate(new Time(c.getTime().getTime()));
				list.add(startRecord);
				list.add(emdRecord);
			}

            Collections.sort(list, new Comparator() {
                public int compare(Object o1, Object o2) {
                  return ((CardRecordInfo)o1).getBizTime().compareTo(((CardRecordInfo)o2).getBizTime());
                }
              });
		} catch (BOSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * 第一次开始打卡是否成功(没有中间休息)
	 * 
	 * @param schEntry
	 *            班表明细
	 * @param cards
	 * @param roundHour
	 *            时间范围(小时)
	 * @return
	 */
	private TimeParam isFinishStartCardByNoRest(ScheduleEntryInfo schEntry,
			List cards, int roundHour) {
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
		TimeParam param = new TimeParam();
		if (cards.size() == 0) {
			// 没有记录
			return param;
		}
		/*else if (cards.size() < 2) {
			// 只有一条打卡记录
			if (((CardRecordInfo) cards.get(0)).getId() != null) {
				// 跨日
				CardRecordInfo recordInfo = (CardRecordInfo) cards.get(0);
				if (compWorkAndCurrByDate(schEntry.getSchDate(),recordInfo.getBizDate())) {
					// 非请假单虚拟记录
					param.cardTime = ((CardRecordInfo) cards.get(0))
							.getBizTime();
				}
			}
			param.isFinish = true;
			return param;
		}*/
		if (schEntry.getSt1() != null) {
			// 班表第一打卡时间
			long stm = schEntry.getSt1().getMinutes()
					+ schEntry.getSt1().getHours() * 60;
			// 提前打卡
			long roundtm = stm - roundHour * 60;
			long lateRoundtm = stm + 60;
			// 时间范围内卡
			for (int i = 0; i < cards.size(); i++) {
				CardRecordInfo recordInfo = (CardRecordInfo) cards.get(i);
				//第二天
				if (!compWorkAndCurrByDate(schEntry.getSchDate(),recordInfo.getBizDate()))  {
					continue;
				}
				long ftm = recordInfo.getBizTime().getMinutes()
						+ recordInfo.getBizTime().getHours() * 60;
				if (roundtm <= ftm && ftm <= stm) {
					// 在时间内打卡，找到第一次打卡时间
					param.isFinish = true;
					// 非请假单虚拟记录
					param.cardTime = recordInfo.getBizTime();
					break;
				} else if (ftm > stm && ftm <= lateRoundtm) {
					// 迟到分钟
					long lateMin = ftm - stm;
					param.isFinish = false;
					// 非请假单虚拟记录
					param.cardTime = recordInfo.getBizTime();
					param.lateTime = lateMin;
					break;
				}
			}

		}
		return param;
	}

	public static boolean compWorkAndCurrByDate(Date workDay, Date currTime) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(workDay);
		c2.setTime(currTime);
		if (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
				&& (c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH))
				&& c1.get(Calendar.DAY_OF_MONTH) == c2
						.get(Calendar.DAY_OF_MONTH)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 结束打卡是否成功(没有中间休息)
	 * 
	 * @param schEntry
	 *            班表明细
	 * @param cards
	 * @return
	 */
	private TimeParam isFinishEndCardByNoRest(ScheduleEntryInfo schEntry,
			List cards, int roundHour) {
		boolean isNextDay = false;
		TimeParam param = new TimeParam();
		if (cards.size() == 0) {
			// 没有记录
			return param;
		} 
		if (schEntry.getEt2() != null) {
			// 班表结束打卡时间
			long etm = schEntry.getEt2().getMinutes()
					+ schEntry.getEt2().getHours() * 60;
			// 当天到下次上班的时间（最早，即使有效时间）
			long roundstm = schEntry.getSt1().getMinutes()
					+ schEntry.getSt1().getHours() * 60 + 24 * 60 - roundHour
					* 60;
			// 上班时间
			long stm = schEntry.getSt1().getMinutes()
					+ schEntry.getSt1().getHours() * 60;
			//早退使用
			long lateRoundtm = stm + 60;

			// long lateRoundtm=stm+60;
			// 时间范围内卡
			for (int i = 0; i < cards.size(); i++) {
				CardRecordInfo recordInfo = (CardRecordInfo) cards.get(i);
				long ltm = recordInfo.getBizTime().getMinutes()
						+ recordInfo.getBizTime().getHours() * 60;

				// 跨日
				if (!compWorkAndCurrByDate(schEntry.getSchDate(),recordInfo.getBizDate())) {
					// 跨日时间
					ltm += 24 * 60;
					isNextDay = true;
				}
				if (schEntry.getSt1().compareTo(schEntry.getEt2()) > 0) {
					// 第二天，跨日
					isNextDay = true;
					// 结束时间为第二天
					etm += 24 * 60;
				}

				if (etm <= ltm && ltm < roundstm) {
					param.isNextDay = isNextDay;
					// 在下次上班时间内打卡，找打结束打卡时间
					param.isFinish = true;

					// 非请假单虚拟记录
					param.cardTime = recordInfo.getBizTime();
					// break;
				}
				// 早退
				if (ltm < etm&&lateRoundtm<ltm) {
					// 非请假单虚拟记录
					param.cardTime = recordInfo.getBizTime();
				}
			}

		}
		return param;
	}
	
	protected void _updateAttenByHolidayBill(Context ctx, String personid,
			Date day) throws BOSException, EASBizException {
		super._updateAttenByHolidayBill(ctx, personid, day);

		// 获取用户HR组织
		String orgHrId = this.getOrgByPersonDate(ctx, personid, day);
		// 没有HR组织，不计算
		if (orgHrId == null)
			return;
		// 获取班组
		String schedulegroup = this.getScheduleForPersonOrg(ctx, personid,
				orgHrId);
		// 没有该HR组织的班组
		if (schedulegroup == null)
			return;
		// 获取该用户班表明细
		ScheduleEntryInfo schEntry = this.getDutyInfo(ctx, schedulegroup,
				day);
		
		if (schEntry == null) {
			return;
		} else {
			// 是否中间休息，如有：4个打卡时间，无：即2个打卡时间
			if (schEntry.isIsRestCard()) {

			} else {
				AttenDetailInfo attenDetailInfo = getAttenDetail(ctx, personid,day);
				if(attenDetailInfo==null)
				{
					return;
				}

				// 正常班和倒班，只需要2个打卡时间
				ArrayList cards = this.getCardRecord(ctx, personid, day);
				// 先处理请假的情况
				// 然后处理实际打卡
				ArrayList cardsHoliday =getHolidayEntryRecord(ctx,personid,day);
				// 合并计算
				cards.addAll(cardsHoliday);

				// 获得开始打卡时间
				TimeParam sparam = isFinishStartCardByNoRest(schEntry, cards, 3);		
				
				// 获得结束打卡时间
				TimeParam eparam = isFinishEndCardByNoRest(schEntry, cards, 3);
				
				if (sparam.isFinish && eparam.isFinish) {
					// 开始时间以及结束时间都完成，表示该班次考勤正常
					attenDetailInfo.setIsClose(true);
				}else {
					attenDetailInfo.setIsClose(false);
				}
				this.save(ctx, attenDetailInfo);
			}
		}
	}

	// @Override
	protected void _calcOnePersonOneDay(Context ctx, String personid, Date d)
			throws BOSException, EASBizException {
		// TODO Auto-generated method stub
		// 计算这个人处于那个组织下

		super._calcOnePersonOneDay(ctx, personid, d);
		calcOnePersonAtten(ctx, personid, d);
		/*
		 * String orgid = this.getOrgByPersonDate(ctx, personid, d); if (orgid
		 * == null )return ; String schedulegroup =
		 * this.getScheduleForPersonOrg(ctx, personid, orgid); if (schedulegroup
		 * == null )return ; ScheduleEntryInfo schEntry = this.getDutyInfo(ctx,
		 * schedulegroup, d); if (schEntry == null )return ; ArrayList cards =
		 * this.getCardRecord(ctx, personid, d);
		 * 
		 * //获取请假记录 ArrayList holiday = null; CheckRegionClass region1= null; if
		 * (schEntry.isIsOffice1() ) { region1 = new CheckRegionClass();
		 * region1.stm = schEntry.getSt1().getMinutes() +
		 * schEntry.getSt1().getHours() 60; region1.etm
		 * =schEntry.getEt1().getMinutes() + schEntry.getEt1().getHours() 60; if
		 * (schEntry.getSt1().compareTo(schEntry.getEt1()) >0) { //第二天
		 * region1.etm = region1.etm + 2460; } } CheckRegionClass region2 =
		 * null; if (schEntry.isIsOffice2()) { region2 = new CheckRegionClass();
		 * region2.stm = schEntry.getSt2().getMinutes() +
		 * schEntry.getSt2().getHours() 60; region2.etm
		 * =schEntry.getEt2().getMinutes() + schEntry.getEt2().getHours() 60; if
		 * (schEntry.getEt1().compareTo(schEntry.getSt2()) >0) { region2.stm =
		 * region2.stm + 2460; } if (region2.stm > region2.etm) { region2.etm =
		 * region2.etm + 2460; } } AttenDetailInfo attenDetailInfo = new
		 * AttenDetailInfo();
		 * 
		 * Iterator itCards = cards.iterator(); boolean ok1 = false; boolean ok2
		 * = false; boolean ok3 = false; boolean ok4 = false; SimpleDateFormat
		 * df = new SimpleDateFormat("yyyy-MM-dd"); while(itCards.hasNext()) {
		 * CardRecordInfo card = (CardRecordInfo)itCards.next(); long t =
		 * card.getBizTime().getMinutes()+ card.getBizTime().getHours()60;
		 * if(df.format(card.getBizDate()).equals(df.format(d)) ==false) { t =
		 * t+ 2460; } if (t <=region1.stm) { //if (ok1 ==false) if (region1.stm
		 * - t <=120) { attenDetailInfo.setSTime1(card.getBizTime()); ok1 =
		 * true; } } else if (t > region1.stm && t<=region1.etm) {
		 * //判断属于上班卡还是下班卡。 if (Math.abs(t -region1.stm) >=
		 * Math.abs(t-region1.etm)) {
		 * attenDetailInfo.setETime1(card.getBizTime()); ok1 = true; ok2 = true;
		 * } else { if (ok1 ==false)
		 * attenDetailInfo.setSTime1(card.getBizTime()); ok1 =true; } } else {
		 * if (region2 == null ) { if (t<2460)
		 * attenDetailInfo.setETime1(card.getBizTime()); } else { if
		 * (Math.abs(t-region1.etm) >= Math.abs(t-region2.stm)) {//这个点属于第二班 if
		 * (Math.abs(t-region2.etm)>=Math.abs(t-region2.stm)) { //这个点归属第二班开始 if
		 * (t<region2.stm) { attenDetailInfo.setSTime2(card.getBizTime()); ok3
		 * =true; } else { if (ok3 ==false) {
		 * attenDetailInfo.setSTime2(card.getBizTime()); ok3 =true; } } } else {
		 * //这个点归属第二班结束 if (t>=region2.etm) { if (t-region2.etm<=120) {
		 * attenDetailInfo.setETime2(card.getBizTime());
		 * 
		 * } ok4 =true; } else { attenDetailInfo.setETime2(card.getBizTime()); }
		 * } } else { //这个点属于第一版，而且是下班点
		 * attenDetailInfo.setETime1(card.getBizTime()); ok2 = true; } } } //
		 * cards.remove(card); if (ok1 && ok2 && ok3 && ok4 ) break; //计算是否完整打卡
		 * if(ok1&&ok4) { attenDetailInfo.setIsClose(true); }else {
		 * attenDetailInfo.setIsClose(false); } }
		 * 
		 * 
		 * PersonInfo person =new PersonInfo();
		 * person.setId(BOSUuid.read(personid)); attenDetailInfo.setEmp(person);
		 * attenDetailInfo.setBizDate(d); try{ EntityViewInfo evi = new
		 * EntityViewInfo(); FilterInfo filter= new FilterInfo();
		 * filter.getFilterItems().add(new FilterItemInfo("emp",personid));
		 * filter.getFilterItems().add(new
		 * FilterItemInfo("bizdate",df.format(d))); this.delete(ctx, filter); }
		 * catch(Exception ex) { ex.printStackTrace(); } this.save(ctx,
		 * attenDetailInfo); //先处理请假的情况 //然后处理实际打卡
		 */

	}

	/**
	 * 根据用户的id和要处理的时间，获取组织的id， 本次暂时实现不考虑时间的当前职位所在的行政组织
	 * 
	 * @param id
	 * @param d
	 * @return
	 */
	protected String getOrgByPersonDate(Context ctx, String id, Date d) {
		PositionInfo positionInfo = null;
		EntityViewInfo entityViewInfo = new EntityViewInfo();
		FilterInfo filterInfo = new FilterInfo();
		filterInfo.getFilterItems().add(
				new FilterItemInfo("person.id", id,
						CompareType.EQUALS));
		entityViewInfo.setFilter(filterInfo);
		IQueryExecutor iqec = QueryExecutorFactory.getLocalInstance(ctx, new MetaDataPK(    
                "com.kingdee.eas.custom.aoyuan.aytime.basedata.app",    
                "PersonHRQuery"));
		try {
			iqec.setObjectView(entityViewInfo);  
			IRowSet irow = iqec.executeQuery();
			if(irow.size()>0)
			{
				if(irow.next())
				{
					 String hrOrgId=irow.getString("HROrgUnit.id");
					 return hrOrgId;
				}
			}
		} catch (BOSException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	/***
	 * 根据职员和 组织，获取班组
	 * 
	 * @param ctx
	 * @param personid
	 * @param orgid
	 * @return
	 */
	protected String getScheduleForPersonOrg(Context ctx, String personid,
			String orgid) {
		try {
			String tmpOrg = orgid;
			while (true) {
				EntityViewInfo evi = new EntityViewInfo();
				FilterInfo filter = new FilterInfo();
				filter.getFilterItems().add(
						new FilterItemInfo("hrorgunit", tmpOrg));
				evi.setFilter(filter);
				SchedulePersonCollection col = SchedulePersonFactory
						.getLocalInstance(ctx).getSchedulePersonCollection(evi);

				if (col.size() > 0) {
					SchedulePersonInfo info = col.get(0);
					Iterator it = info.getEntrys().iterator();
					while (it.hasNext()) {
						SchedulePersonEntryInfo entry = (SchedulePersonEntryInfo) it
								.next();
						if (entry.getEmp() != null
								&& entry.getEmp().getId().toString().equals(
										personid)) {
							return null;
						}
					}
					it = info.getSpecSchl().iterator();
					while (it.hasNext()) {
						SchedulePersonSpecSchlInfo entry = (SchedulePersonSpecSchlInfo) it
								.next();
						if (entry.getEmp() != null
								&& entry.getEmp().getId().toString().equals(
										personid)
								&& entry.getSchgroup() != null) {
							return entry.getSchgroup().getId().toString();
						}
					}
					if (info.getDefaultSchlGroup() != null) {
						return info.getDefaultSchlGroup().getId().toString();
					}

					// 找上级
					String strSQL = "Select FParentID from t_org_baseunit where FID = '"
							+ tmpOrg + "'";
					IRowSet rs = DbUtil.executeQuery(ctx, strSQL);
					if (rs.next()) {
						String org = rs.getString("FParentID");
						if (org == null || org.equals(tmpOrg))
							return null;
						tmpOrg = org;
					} else {
						return null;
					}
				} else {
					return null;
				}

			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	protected ArrayList getCardRecord(Context ctx, String personid, Date d) {
		ArrayList ar = new ArrayList();
		try {
			Calendar c = Calendar.getInstance();
			c.setTime(d);
			c.set(Calendar.HOUR, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			Date startDate = c.getTime();
			c.setTime(d);
			c.set(Calendar.HOUR, 23);
			c.set(Calendar.MINUTE, 59);
			c.set(Calendar.SECOND, 59);
			c.add(Calendar.DAY_OF_YEAR, 1);
			Date endDate = c.getTime();
			// SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			EntityViewInfo evi = new EntityViewInfo();
			FilterInfo filter = new FilterInfo();
			filter.getFilterItems().add(new FilterItemInfo("emp", personid));
			filter.getFilterItems().add(
					new FilterItemInfo("BizDate", startDate,
							CompareType.GREATER_EQUALS));
			filter.getFilterItems().add(
					new FilterItemInfo("BizDate", endDate,
							CompareType.LESS_EQUALS));
			// Calendar c = Calendar.getInstance();

			// c.setTime(d);
			// c.add(Calendar.DAY_OF_YEAR, 1);
			// filter.getFilterItems().add(new
			// FilterItemInfo("BizDate",df.format
			// (c.getTime()),CompareType.EQUALS));
			// filter.setMaskString("#0 and (#1 or  #2)");
			SorterItemCollection sic = new SorterItemCollection();
			sic.add(new SorterItemInfo("bizDate"));
			sic.add(new SorterItemInfo("bizTime"));
			evi.setFilter(filter);
			evi.setSorter(sic);
			CardRecordCollection cards = CardRecordFactory
					.getLocalInstance(ctx).getCardRecordCollection(evi);
			Iterator it = cards.iterator();
			while (it.hasNext()) {
				CardRecordInfo info = (CardRecordInfo) it.next();
				ar.add(info);
			}

			return ar;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return ar;
	}

	protected ScheduleEntryInfo getDutyInfo(Context ctx, String groupid, Date d) {
		try {
			SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
			SimpleDateFormat dfMonth = new SimpleDateFormat("M");
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			EntityViewInfo evi = new EntityViewInfo();
			FilterInfo filter = new FilterInfo();
			filter.getFilterItems().add(new FilterItemInfo("group", groupid));
			filter.getFilterItems().add(
					new FilterItemInfo("year", dfYear.format(d)));
			filter.getFilterItems().add(
					new FilterItemInfo("month", dfMonth.format(d)));
			evi.setFilter(filter);
			ScheduleCollection col = ScheduleFactory.getLocalInstance(ctx)
					.getScheduleCollection(evi);
			if (col.size() == 0)
				return null;

			ScheduleInfo info = col.get(0);

			Iterator it = info.getEntrys().iterator();
			while (it.hasNext()) {
				ScheduleEntryInfo entry = (ScheduleEntryInfo) it.next();
				if(entry.isIsOffice1())
				{
					if (entry.getSchDate() != null) {
						if (df.format(entry.getSchDate()).equals(df.format(d))) {
							return entry;
						}
					}					
				}
			}
			return null;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}
}